<template>
  <Top-Page class="container">
    <cu-custom bgColor="bg-gradual-white-3" :isBack="true">
      <template #content>深度</template>
    </cu-custom>

    <!-- 聊天内容区域 -->
    <view class="chat-container">
      <view v-for="(msg, index) in messages" :key="index" :id="'msg' + index" class="message" :class="[msg.role]">
        <template v-if="msg.role === 'user'">
          <text class="content user-wrap">{{ msg.content }}</text>
        </template>
        <template v-else>
          <text class="content" v-html="formatContent(msg.content)"></text>
        </template>

        <!-- <view v-if="msg.loading" class="loading">思考中...</view> -->
        <view v-if="msg.loading" class="loading">
          <span class="loading-text">思考中</span>
          <span class="loading-dots">
            <span class="dot">.</span>
            <span class="dot">.</span>
            <span class="dot">.</span>
          </span>
        </view>
      </view>
    </view>

    <!-- 输入区域 -->
    <view class="input-container">
      <textarea
        :fixed="true"
        maxlength="200"
        :auto-height="true"
        cursor-spacing="10"
        type="text"
        class="input"
        v-model="inputText"
        placeholder="请输入内容"
        :disabled="isLoading"
        @confirm="send"
      />

      <view :class="['send-btn', { 'send-disabled': !inputText || isLoading }]" @click="send">
        {{ isLoading ? "发送中..." : "发送" }}
      </view>
    </view>
  </Top-Page>
</template>

<script lang="ts" setup>
import msgApi from "@/api/message.js";
import { funThrottle } from "@/utils/fun";
import { ref, nextTick, getCurrentInstance } from "vue";

interface ChatMessage {
  role: "user" | "assistant";
  content: string;
  loading?: boolean;
}

const instance = getCurrentInstance(); // 获取组件实例

const inputText = ref("");
const isLoading = ref(false);
const messages = ref<ChatMessage[]>([]);

// 滚动到底部
const scrollToBottom = funThrottle(() => {
  if (messages.value.length > 0) {
    let query = uni.createSelectorQuery().in(instance);
    query
      .select(".container")
      .boundingClientRect((data) => {
        data &&
          data.height &&
          uni.pageScrollTo({
            scrollTop: data.height,
          });
      })
      .exec();
  }
});

uni.$on("getPositonsOrder", (res) => {
  let msg = res.data;
  switch (res["type"]) {
    case "Ai":
      const assistantIndex = messages.value.length - 1;
      if (msg.status === 0) {
        //失败
        messages.value.push({
          role: "assistant",
          content: "请求失败，请稍后重试",
        });
        isLoading.value = false;
      }
      if (msg.status === 1) {
        //接收中
        messages.value[assistantIndex].content += msg.content;
        const lastMessage = messages.value[messages.value.length - 1];
        if (lastMessage?.loading) {
          delete lastMessage.loading;
        }

        scrollToBottom();
      }
      if (msg.status === 2) {
        //结束
        isLoading.value = false;
      }

      break;
  }
});

const send = () => {
  if (!inputText.value.trim() || isLoading.value) return;

  isLoading.value = true;
  const userMessage = JSON.parse(JSON.stringify(inputText.value));
  inputText.value = "";

  // 添加用户消息
  messages.value.push({
    role: "user",
    content: userMessage,
  });

  // 添加初始助手消息
  messages.value.push({
    role: "assistant",
    content: "",
    loading: true,
  });

  nextTick(() => {
    scrollToBottom();
  });

  msgApi
    .ai({ content: userMessage })
    .then((res) => {})
    .catch((err) => {
      messages.value.push({
        role: "assistant",
        content: "请求失败，请稍后重试",
      });
      isLoading.value = false;
    });
};

interface ReplacementRule {
  pattern: RegExp;
  replacer: string | ((substring: string, ...args: any[]) => string);
}
const formatContent = (text: string): string => {
  // 1. 预处理 math 块：匹配 \[ ... \] 内的数学公式
  const mathBlockRegex = /\\\[(.*?)\\\]/gs;
  let mathBlocks: string[] = [];
  text = text.replace(mathBlockRegex, (match, content) => {
    mathBlocks.push(content);
    return `@@MATH_BLOCK_${mathBlocks.length - 1}@@`;
  });

  // 2. 进行 HTML 转义，防止 XSS 等问题
  let escapedText = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

  // 3. 恢复 math 块，包裹成自定义标签，保留原始的数学命令（如 \text 等）
  mathBlocks.forEach((block, index) => {
    const mathHtml = `<span class="math">\\[${block}\\]</span>`;
    escapedText = escapedText.replace(`@@MATH_BLOCK_${index}@@`, mathHtml);
  });

  // 4. 处理代码块，避免后续替换干扰代码内容
  escapedText = escapedText.replace(
    /```([\s\S]*?)```/g,
    (_, code) => `<pre class="content-pre"><code>${code.trim()}</code></pre>`
  );

  // 5. 处理标题（目前支持 ### 级别标题）
  escapedText = escapedText.replace(/###\s+(.+)/g, '<h3 class="content-h3">$1</h3>');

  // 6. 内联格式处理（支持加粗和斜体）
  const processInline = (line: string): string => {
    return line
      .replace(/\*\*(.*?)\*\*/g, '<strong class="content-strong">$1</strong>')
      .replace(/\*(.*?)\*/g, '<em class="content-em">$1</em>');
  };

  // 7. 按行处理文本，分组处理列表与普通段落
  const lines = escapedText.split("\n");
  let output = "";
  let listStack: { type: "ol" | "ul"; indent: number }[] = [];

  // 辅助函数：关闭缩进大于等于 targetIndent 的所有列表
  const closeListsTo = (targetIndent: number) => {
    while (listStack.length && listStack[listStack.length - 1].indent >= targetIndent) {
      const list = listStack.pop();
      output += list!.type === "ol" ? "</ol>" : "</ul>";
    }
  };

  lines.forEach((line) => {
    const indentMatch = line.match(/^(\s*)/);
    const indent = indentMatch ? indentMatch[1].length : 0;
    const trimmedLine = line.trim();

    // 匹配有序列表项
    const orderedMatch = trimmedLine.match(/^(\d+)\.\s+(.+)/);
    // 匹配无序列表项
    const unorderedMatch = trimmedLine.match(/^-\s+(.+)/);

    if (orderedMatch) {
      if (
        listStack.length === 0 ||
        listStack[listStack.length - 1].type !== "ol" ||
        listStack[listStack.length - 1].indent < indent
      ) {
        output += "<ol>";
        listStack.push({ type: "ol", indent });
      } else if (listStack[listStack.length - 1].indent > indent) {
        closeListsTo(indent);
        if (listStack.length === 0 || listStack[listStack.length - 1].type !== "ol") {
          output += "<ol>";
          listStack.push({ type: "ol", indent });
        }
      }
      const originalNum = orderedMatch[1];
      output += `<li value="${originalNum}" class="content-ol-li">${processInline(orderedMatch[2])}</li>`;
    } else if (unorderedMatch) {
      if (
        listStack.length === 0 ||
        listStack[listStack.length - 1].type !== "ul" ||
        listStack[listStack.length - 1].indent < indent
      ) {
        output += "<ul>";
        listStack.push({ type: "ul", indent });
      } else if (listStack[listStack.length - 1].indent > indent) {
        closeListsTo(indent);
        if (listStack.length === 0 || listStack[listStack.length - 1].type !== "ul") {
          output += "<ul>";
          listStack.push({ type: "ul", indent });
        }
      }
      output += `<li class="content-li">${processInline(unorderedMatch[1])}</li>`;
    } else {
      closeListsTo(0);
      if (trimmedLine) {
        output += `<p class="content-p">${processInline(trimmedLine)}</p>`;
      }
    }
  });
  // 结束时关闭所有未关闭的列表
  closeListsTo(0);

  return output;
};
</script>

<style lang="scss">
.container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: #f4f4f4;
}

.content {
  flex: 1;
  display: flex;
  flex-direction: column;
  font-size: 28rpx;
  line-height: 1.6;
  color: #333;

  /* 标题样式 */
  .content-h3 {
    font-size: 1.5em;
    margin: 1em 0;
    font-weight: bold;
    border-bottom: 1px solid #eaeaea;
    padding-bottom: 0.3em;
  }

  /* 加粗与斜体 */
  .content-strong {
    font-weight: bold;
  }
  .content-em {
    font-style: italic;
  }

  /* 列表样式 */
  .content-li,
  .content-ol-li {
    margin-left: 1.5em;
    line-height: 1.6;
  }
  ul,
  ol {
    padding-left: 1em;
    margin: 0.5em 0;
  }

  /* 代码块样式 */
  .content-pre {
    background-color: #f5f5f5;
    padding: 1em;
    overflow: auto;
    border-radius: 4px;
    margin: 1em 0;
  }
  .content-pre code {
    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
    white-space: pre-wrap;
  }

  /* 段落样式 */
  .content-p {
    margin: 0.5em 0;
    line-height: 1.6;
  }
}

.user-wrap {
  padding: 9rpx 0;
}

.chat-container {
  flex: 1;
  padding: 20rpx;
  padding-bottom: 100rpx;
  overflow-y: auto;
}

.message {
  margin: 20rpx 0;
  padding: 8rpx 20rpx;
  border-radius: 10rpx;
  max-width: 80%;
  width: fit-content; /* 自动适应内容宽度 */
  box-sizing: border-box;
  word-wrap: break-word; /* 长单词或URL自动换行 */
  font-size: 28rpx;
  line-height: 1.6;

  &.user {
    background: #bee0ff;
    margin-left: auto;
  }

  &.assistant {
    background: #ffffff;
    margin-right: auto;
  }

  .loading {
    display: flex;
    align-items: center;
    color: #666;
    padding: 10rpx;
  }

  .loading-text {
    animation: pulse 1.5s ease-in-out infinite;
  }

  .loading-dots {
    letter-spacing: 6rpx;
  }

  .dot {
    display: inline-block;
    animation: bounce 1.4s infinite ease-in-out;
  }

  .dot:nth-child(1) {
    animation-delay: 0s;
  }
  .dot:nth-child(2) {
    animation-delay: 0.2s;
  }
  .dot:nth-child(3) {
    animation-delay: 0.4s;
  }

  @keyframes pulse {
    0%,
    100% {
      opacity: 0.8;
    }
    50% {
      opacity: 1;
    }
  }

  @keyframes bounce {
    0%,
    100% {
      transform: translateY(0);
      opacity: 0.6;
    }
    50% {
      transform: translateY(-3px);
      opacity: 1;
    }
  }
}

.input-container {
  width: 100%;
  position: fixed;
  bottom: 0;
  left: 0;
  display: flex;
  align-items: center;
  padding: 10rpx 20rpx;
  border-top: 1rpx solid #eee;
  background: #fff;

  .input {
    flex: 1;
    max-height: 4em;
    overflow-x: auto;
    margin-right: 20rpx;
    padding: 15rpx;
    border: 1rpx solid #ccc;
    border-radius: 8rpx;
  }

  .send-btn {
    flex-shrink: 0;
    padding: 20rpx 30rpx;
    background: #007aff;
    color: white;
    border-radius: 8rpx;
  }

  .send-disabled {
    opacity: 0.5;
  }
}
</style>
